热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

可能会|这一点_虚幻引擎UI组件开发快速入门UMG/Slate

篇首语:本文由编程笔记#小编为大家整理,主要介绍了虚幻引擎UI组件开发快速入门UMG/Slate相关的知识,希望对你有一定的参考价值。Unreal的UMG提供了相当

篇首语:本文由编程笔记#小编为大家整理,主要介绍了虚幻引擎UI组件开发快速入门UMG/Slate相关的知识,希望对你有一定的参考价值。


Unreal 的 UMG 提供了相当多的UI Widget,并允许你在蓝图中做很多事情。但是,有时可能仍需要创建自定义Widget来填补空白。这篇文章中将介绍使用自定义渲染创建Slate Widget的基础知识。

UMG Widget涉及两个类:


  • 一个 UWidget 派生类,可以在编辑器中与之交互
  • 一个 SCompoundWidget 类,处理低级功能和渲染

让我们看一个展示切片的简单UMG Widget,它具有给定的起始角度和圆弧大小。我们可以控制颜色和不透明度,并且可以选择使用图像来渲染它:


1、最小UMG Widget类

首先,我们将添加没有任何功能的类,并确保我们看到新的小部件出现在编辑器面板中。

这是一个 UMG 小部件的最小化头文件:

UCLASS()
class CUSTOMWIDGET_API USlice : public UWidget
GENERATED_BODY()
public:
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
protected:
virtual TSharedRef RebuildWidget() override;
TSharedPtr MySlice;
;
对应的CPP文件如下:
void USlice::ReleaseSlateResources(bool bReleaseChildren)
MySlice.Reset();
TSharedRef USlice::RebuildWidget()
MySlice = SNew(SSlateSlice);
return MySlice.ToSharedRef();

请注意,在创建新UMG Widget时,始终必须实现这两个方法 - RebuildWidget负责构建 Slate Widget, ReleaseSlateResources负责清理资源。


2、最小Slate Widget类

这是 UMG Widget类引用的 Slate 类:

class CUSTOMWIDGET_API SSlateSlice : public SCompoundWidget
public:
SLATE_BEGIN_ARGS(SSlateSlice)

SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
;

以及对应的CPP文件:

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlateSlice::Construct(const FArguments& InArgs)

END_SLATE_FUNCTION_BUILD_OPTIMIZATION
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION和END_SLATE_FUNCTION_BUILD_OPTIMIZATION经常在Construct函数周围使用,因为它最终可能会产生一个非常复杂的表达式,编译器可能会花费大量时间来尝试优化。这些宏关闭并再次打开优化。


3、传递Widget属性

为了让我们的UMG Widget绘制切片,需要添加一些属性来确定它的外观。首先,我们将Brush、Angle和ArcSize添加到 UMG Widget:

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance")
FSlateBrush Brush;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance")
float Angle;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance")
float ArcSize;

我们还需要在 Slate 类中添加类似的属性。它们都作为参数添加到 SLATE_BEGIN_ARGS / SLATE_END_ARGS宏中,以及类中的常规成员变量:

SLATE_BEGIN_ARGS(SSlateSlice)

SLATE_ARGUMENT(FSlateBrush*, Brush)
SLATE_ARGUMENT(float, Angle)
SLATE_ARGUMENT(float, ArcSize)
SLATE_END_ARGS()

...

protected:
FInvalidatableBrushAttribute Brush;
float Angle;
float ArcSize;

RebuildWidget方法需要将这些属性从 UMG Widget传递给 Slate Widget:

TSharedRef USlice::RebuildWidget()
MySlice = SNew(SSlateSlice)
.Brush(&Brush)
.Angle(Angle)
.ArcSize(ArcSize);
return MySlice.ToSharedRef();

Slate Widget现在将这些属性作为Construct方法的参数获取:

void SSlateSlice::Construct(const FArguments& InArgs)
Brush = FInvalidatableBrushAttribute(InArgs._Brush);
Angle = InArgs._Angle;
ArcSize = InArgs._ArcSize;

在类头中定义的每个SLATE_ARGUMENT作为成员添加到FArguments结构中,并在其名称前加上下划线。Construct方法只是将这些值复制到类成员变量中,以便稍后在渲染Widget时使用它们。


4、Widget渲染

现在我们终于可以添加OnPaint方法了,它处理Widget的实际渲染。

在这一点上,我不会详细介绍所有参数 - 以下是我们在以下方法中引用的参数:


  • AllottedGeometry为我们提供了Widget的位置和大小
  • OutDrawElements接收用于渲染Widget的绘制元素
  • nWidgetStyle为我们提供了应该应用的颜色和不透明度

FSlateDrawElement 是渲染 Slate Widget的主力。它具有绘制框、线、文本、样条线等的方法。我们将在这里使用顶点(在 2D 空间中)和索引来渲染任意网格。

我们需要为顶点填充 FSlateVertex 结构的 TArray,以及定义从顶点构建的三角形的 SlateIndex (uint32) 索引值的 TArray。

为了渲染切片,我们在中心添加一个顶点,然后沿弧添加边缘顶点。然后索引缓冲区使用中心和一对连续的边顶点定义三角形。每个顶点的颜色是通过使用通过小部件样式传入的颜色和不透明度以及小部件的整体颜色和不透明度来调制画笔颜色来计算的。

如果画笔使用图像,我们也可以为顶点设置 UV 坐标——我暂时不考虑它。

int32 SSlateSlice::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect,
FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle,
bool bParentEnabled) const
const FVector2D Pos = AllottedGeometry.GetAbsolutePosition();
const FVector2D Size = AllottedGeometry.GetAbsoluteSize();
const FVector2D Center = Pos + 0.5 * Size;
const float Radius = FMath::Min(Size.X, Size.Y) * 0.5f;
const FSlateBrush* SlateBrush = Brush.GetImage().Get();
FLinearColor LinearColor = ColorAndOpacity.Get() * InWidgetStyle.GetColorAndOpacityTint() * SlateBrush->GetTint(InWidgetStyle);
FColor FinalColorAndOpacity = LinearColor.ToFColor(true);
const int NumSegments = FMath::RoundToInt(ArcSize / 10.0f);
TArray Vertices;
Vertices.Reserve(NumSegments + 3);
// Add center vertex
Vertices.AddZeroed();
FSlateVertex& CenterVertex = Vertices.Last();
CenterVertex.Position = Center;
CenterVertex.Color = FinalColorAndOpacity;
// Add edge vertices
for (int i = 0; i
const float CurrentAngle = FMath::DegreesToRadians(ArcSize * i / NumSegments + Angle);
const FVector2D EdgeDirection(FMath::Cos(CurrentAngle), FMath::Sin(CurrentAngle));
const FVector2D OuterEdge(Radius*EdgeDirection);
Vertices.AddZeroed();
FSlateVertex& OuterVert = Vertices.Last();
OuterVert.Position = Center + OuterEdge;
OuterVert.Color = FinalColorAndOpacity;

TArray Indices;
for (int i = 0; i
Indices.Add(0);
Indices.Add(i);
Indices.Add(i + 1);

const FSlateResourceHandle Handle = FSlateApplication::Get().GetRenderer()->GetResourceHandle( *SlateBrush );
FSlateDrawElement::MakeCustomVerts(
OutDrawElements,
LayerId,
Handle,
Vertices,
Indices,
nullptr,
0,
0
);
return LayerId;

这允许我们以不同的大小和颜色渲染切片:


5、更新Widget属性

为了使编辑器正常工作,我们需要在 Slate 小部件中的属性在 UMG 小部件中发生更改时更新它们。我们通过重写SynchronizeProperties函数来做到这一点:

void USlice::SynchronizeProperties()
Super::SynchronizeProperties();
MySlice->SetBrush(&Brush);
MySlice->SetAngle(Angle);
MySlice->SetArcSize(ArcSize);

Slate 小部件需要以下 setter 函数:

void SSlateSlice::SetBrush(FSlateBrush* InBrush)
Brush.SetImage(*this, InBrush);
void SSlateSlice::SetAngle(float InAngle)
Angle = InAngle;
void SSlateSlice::SetArcSize(float InArcSize)
ArcSize = InArcSize;

现在,只要在编辑器中更改任何属性,切片就会立即更新。


6、设置Widget类别

除非另行指定,否则Widget在 UMG 设计器的Widget面板中显示为未分类。要设置类别,请添加对GetPaletteCategory函数的覆盖:

#if WITH_EDITOR
const FText USlice::GetPaletteCategory()
return LOCTEXT("CustomPaletteCategory", "My custom category!");
#endif


7、后续工作

本文涉及的源码可以从 GitHub 库中下载。

在能够与 Unreal 中的常规 UMG Widget相提并论之前,仍有许多工作要做。例如,属性不支持动画,也不支持属性绑定。我也没有讨论鼠标事件——UMG(和 Slate)中的所有Widget都是矩形的,因此在不规则形状的Widget上正确处理鼠标需要一些技巧。

实现自定义Widget的一个潜在原因是优化 - 例如,实现一个组合多个元素呈现的单个Widget可能会更快 - 我将在不久的将来探讨这一点。



原文链接:Slate Widget开发教程 — BimAnt


推荐阅读
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • 通过Anaconda安装tensorflow,并安装运行spyder编译器的完整教程
    本文提供了一个完整的教程,介绍了如何通过Anaconda安装tensorflow,并安装运行spyder编译器。文章详细介绍了安装Anaconda、创建tensorflow环境、安装GPU版本tensorflow、安装和运行Spyder编译器以及安装OpenCV等步骤。该教程适用于Windows 8操作系统,并提供了相关的网址供参考。通过本教程,读者可以轻松地安装和配置tensorflow环境,以及运行spyder编译器进行开发。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了StartingzookeeperFAILEDTOSTART相关的知识,希望对你有一定的参考价值。下载路径:https://ar ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
author-avatar
流连的瓶子
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有